package service

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/url"
	"ollama-go/dto"
	"ollama-go/entity"
	"ollama-go/query"
	"ollama-go/toolkit"
	"ollama-go/vo"
	"os"
	"path/filepath"
	"strings"

	"github.com/androidsr/sc-go/model"
	"github.com/androidsr/sc-go/sbuilder"
	"github.com/androidsr/sc-go/sc"
	"github.com/androidsr/sc-go/sgorm"
	"github.com/androidsr/sc-go/shttp"
	"github.com/androidsr/sc-go/sno"
	"github.com/tmc/langchaingo/llms"
)

var apiRequestConfigService *ApiRequestConfigService

type ApiRequestConfigService struct {
}

func NewApiRequestConfigService() *ApiRequestConfigService {
	if apiRequestConfigService == nil {
		apiRequestConfigService = new(ApiRequestConfigService)
	}
	return apiRequestConfigService
}

// 使用id获取数据
func (m ApiRequestConfigService) Get(id string) *vo.ApiRequestConfigVO {
	data := new(entity.ApiRequestConfig)
	data.Id = id
	err := sgorm.DB.GetOne(data)
	if err != nil {
		return nil
	}
	return sc.Copy[vo.ApiRequestConfigVO](data)
}

// 保存数据
func (m ApiRequestConfigService) Save(dto *dto.ApiRequestConfigDTO) error {
	data := sc.Copy[entity.ApiRequestConfig](dto)
	data.Id = sno.GetString()
	err := sgorm.DB.Insert(data)
	return err
}

func (m ApiRequestConfigService) SaveOrUpdate(dto *dto.ApiRequestConfigDTO) error {
	var err error
	data := new(entity.ApiRequestConfig)
	data.Id = dto.Id
	err = sgorm.DB.GetOne(data)
	if err != nil {
		return err
	}
	if data == nil && dto.Id == "" {
		err = m.Save(dto)
	} else {
		if data.ApiName != dto.ApiName {
			dto.Id = ""
			err = m.Save(dto)
		} else {
			err = m.UpdateById(dto)
		}
	}
	return err
}

// 更新数据
func (m ApiRequestConfigService) UpdateById(dto *dto.ApiRequestConfigDTO) error {
	dbEntity := new(entity.ApiRequestConfig)
	dbEntity.Id = dto.Id
	sgorm.DB.GetOne(dbEntity)
	if dbEntity.TenantId != "" && dbEntity.TenantId != dto.TenantId {
		return errors.New("非本人创建不能修改")
	}
	sc.CopyTo(dto, dbEntity)
	err := sgorm.DB.UpdateById(dbEntity).Error
	return err
}

// 删除数据
func (m ApiRequestConfigService) DeleteById(id string) error {
	err := sgorm.DB.DeleteById(entity.ApiRequestConfig{}, id)
	return err
}

// 删除数据
func (m ApiRequestConfigService) DeleteByPlatformId(id string) error {
	err := sgorm.DB.Delete(entity.ApiRequestConfig{}, entity.ApiRequestConfig{PlatformId: id}).Error
	return err
}

// 分页列表查询
func (m ApiRequestConfigService) QueryPage(query *query.ApiRequestConfigQueryDTO) *model.PageResult {
	sql := `select * from api_request_config a `
	data := make([]entity.ApiRequestConfig, 0)
	b := sbuilder.StructToBuilder(query, sql)
	sql, values := b.Build()
	return sgorm.DB.SelectPage(&data, query.BaseQueryDTO.Page, sql, values...)
}

// 分页下拉查询
func (m ApiRequestConfigService) QueryList(query *model.SelectQueryDTO) *model.PageResult {
	sql := `select a.id as value, a.use_name as label from api_request_config a where 1=1 `
	data := make([]model.SelectVO, 0)
	b := sbuilder.Builder(sql)
	b.Like("CONCAT(a.id,a.use_name)", query.Label)
	for k, v := range query.Vars {
		b.Eq(k, v)
	}
	b.Multiple().Ors(b.In("a.id", query.Selected))
	sql, values := b.Build()
	return sgorm.DB.SelectPage(&data, &query.Page, sql, values...)
}

// AI获取接口信息
func (m ApiRequestConfigService) AiRecognitionApi(dto *dto.ApiRequestDTO) any {
	chat := toolkit.GetLLM("")
	filePath := dto.ApiForm.FilePath
	if strings.HasPrefix(filePath, "file:/") {
		filePath = strings.Replace(filePath, "file:/", "", 1)
	}
	bs, err := os.ReadFile(filePath)
	if err != nil {
		return model.NewFailDefault("读取文件失败")
	}
	dto.PlatformForm.WorkDir = "d:/dev/java/work/coos-boot-parent"
	template := `
		文件路径：%s
		文件内容：%s
		公共对象：%s
		根据指定方法名称提取入参数的类名称。
		并用"$RESULT"和"$END"作为包裹标志。
		确保不会返回除类名称以外的任何其他内容。
		示例：
		$RESULT类名称$END
	`
	chat.SetContent(llms.TextParts(llms.ChatMessageTypeSystem, fmt.Sprintf(template, filePath, string(bs), dto.PlatformForm.Extends)))
	chat.SetContent(llms.TextParts(llms.ChatMessageTypeHuman, dto.ApiForm.ApiName))
	data := bytes.Buffer{}
	_, err = chat.GenerateCallback(context.Background(), func(ctx context.Context, chunk []byte) error {
		data.Write(chunk)
		return nil
	})
	if err != nil {
		log.Printf("AI失败：%s", err.Error())
		return model.NewFailDefault("AI生成失败")
	}
	log.Println(data.String())
	filename := data.String()[7 : len(data.String())-4]
	chat = toolkit.GetLLM("")
	paramsFile := bytes.Buffer{}
	if filename != "" && !strings.Contains(filename, ",") {
		filepath.Walk(dto.PlatformForm.WorkDir, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if info.IsDir() {
				return nil
			}
			idx := strings.LastIndex(info.Name(), ".")
			if idx == -1 {
				idx = 1
			}
			if strings.HasSuffix(info.Name(), ".class") {
				return nil
			}
			if info.Name()[:idx] == filename {
				bs, err := os.ReadFile(path)
				if err != nil {
					return err
				}
				paramsFile.Write(bs)
			}
			return nil
		})
		template := `
		文件内容：%s
		参数对象：%s
		公共对象：%s
		根据输入信息，提取出山指定方法所需要的接口请求要素。
		要求包含信息有：(apiName=接口名称，apiUrl=接口地址，requestMethod=请求方式(GET,POST,PUT,DELETE)，数据类型=requestType(application/json,application/x-www-form-urlencoded,multipart/form-data,text/html)，requestParams=请求体),
		请求体中的字段信息生成一个JSON字符串。
		并用"$RESULT"和"$END"作为包裹标志。
		请确保返回的JSON字符串中无注释。
		确保不会返回除参数以外的任何其他内容。
		JSON格式示例：
		$RESULT{
			"apiUrl":"",
			"requestMethod":"",
			"requestType":"",
			"requestParams": "",
		}$END
	`
		chat.SetContent(llms.TextParts(llms.ChatMessageTypeSystem, fmt.Sprintf(template, string(bs), paramsFile.String(), dto.PlatformForm.Extends)))
		chat.SetContent(llms.TextParts(llms.ChatMessageTypeHuman, dto.ApiForm.ApiName))
		data = bytes.Buffer{}
		_, err = chat.GenerateCallback(context.Background(), func(ctx context.Context, chunk []byte) error {
			data.Write(chunk)
			return nil
		})
		if err != nil {
			log.Printf("AI失败：%s", err.Error())
			return model.NewFailDefault("AI生成失败")
		}
		fmt.Println(data.String())
		if data.String() == "" {
			return model.NewFailDefault("AI生成数据为空")
		}
		resultStr := data.String()[7 : len(data.String())-4]
		resultMap := make(map[string]any, 0)
		json.Unmarshal([]byte(resultStr), &resultMap)
		return model.NewOK(resultMap)
	}

	return nil
}

// 发送请求
func (m ApiRequestConfigService) Send(dto *dto.ApiRequestDTO) any {
	baseUrl := dto.PlatformForm.ApiPlatformInfo.BaseUrl + dto.ApiForm.ApiUrl
	headerStr := dto.PlatformForm.Headers
	cookieStr := dto.PlatformForm.Cookies
	method := dto.ApiForm.RequestMethod
	contentType := dto.ApiForm.RequestType

	params := make(map[string]interface{}, 0)
	if dto.ApiForm.RequestMethod != "GET" && dto.ApiForm.RequestParams != "" {
		err := json.Unmarshal([]byte(dto.ApiForm.RequestParams), &params)
		if err != nil {
			return errors.New("参数格式不正确！")
		}
	}
	headers := make(map[string]string, 0)
	if headerStr != "" {
		kvs := strings.Split(headerStr, ";")
		for _, v := range kvs {
			if strings.Contains(v, "=") {
				kv := strings.Split(v, "=")
				headers[kv[0]] = kv[1]
			}
		}
	}
	if cookieStr != "" {
		headers["Cookie"] = cookieStr
	}
	var data []byte
	var err error
	switch method {
	case "GET":
		values := url.Values{}
		for k, v := range params {
			values.Set(k, fmt.Sprint(v))
		}
		data, err = shttp.Get(baseUrl+"?"+values.Encode(), contentType, headers)
	case "POST":
		data, err = shttp.Post(baseUrl, strings.TrimSpace(contentType), headers, params)
	case "PUT":
		data, err = shttp.Put(baseUrl, contentType, headers, params)
	case "DELETE":
		data, err = shttp.Delete(baseUrl, contentType, headers, params)
	}
	if err != nil {
		return err
	}

	var result interface{}
	resultMap := make(map[string]interface{}, 0)
	err = json.Unmarshal(data, &resultMap)
	if err != nil {
		result = string(data)
	} else {
		result = resultMap
	}

	err = NewApiPlatformInfoService().SaveOrUpdate(&dto.PlatformForm)
	if err != nil {
		return err
	}
	dto.ApiForm.PlatformId = dto.PlatformForm.Id
	err = NewApiRequestConfigService().SaveOrUpdate(&dto.ApiForm)
	if err != nil {
		return err
	}
	return result
}
